/*
 * Buffer.h
 *
 *  Created on: Aug 18, 2011
 *      Author: mengwei.chua
 */

#ifndef BUFFER_H_
#define BUFFER_H_

#include <string.h>

#define DEFAULT_CAPACITY 1024

namespace projectcos
{
namespace common
{

template<typename T>
class Buffer
{
public:
	Buffer()
	: m_Data(NULL)
	, m_Size(0u)
	, m_Capacity(DEFAULT_CAPACITY)
	{
		m_Data = new T[m_Capacity];
		memset(m_Data, 0, sizeof(T) * m_Capacity);
	}

	Buffer(unsigned int capacity)
	: m_Data(NULL)
	, m_Size(0u)
	, m_Capacity(capacity)
	{
		m_Data = new T[capacity];
		memset(m_Data, 0, sizeof(T) * m_Capacity);
	}

	Buffer(T* data, unsigned int size)
	: m_Data(NULL)
	, m_Size(size)
	, m_Capacity(DEFAULT_CAPACITY)
	{
		if(size >= DEFAULT_CAPACITY)
		{
			m_Capacity *= 2;
		}

		m_Data = new T[m_Capacity];
		memset(m_Data, 0, sizeof(T) * m_Capacity);
		memcpy(m_Data, data, sizeof(T) * size);
	}

	Buffer(const Buffer<T>& copy)
	{
		*this = copy;
	}

	Buffer<T>& operator=(const Buffer<T>& copy)
	{
		Reserve(copy.GetCapacity());
		Append(copy.GetData(), copy.GetSize());

		return *this;
	}

	~Buffer()
	{
		if(NULL != m_Data)
		{
			delete [] m_Data;
		}
	}

	void Reserve(unsigned int capacity)
	{
		T* tempData = new T[capacity];
		m_Capacity = capacity;
		memset(tempData, 0, sizeof(T) * m_Capacity);
		memcpy(tempData, m_Data, sizeof(T) * ((capacity >= m_Size) ? m_Size : capacity));

		delete [] m_Data;
		m_Data = tempData;
	}

	inline T operator[](const int index) const
	{
		return m_Data[index];
	}

	void Append(const T data)
	{
		if(m_Size >= m_Capacity)
		{
			Reserve(m_Capacity * 2);
		}

		m_Data[m_Size++] = data;
	}

	void Append(T const* data, unsigned int size)
	{
		if(m_Size + size >= m_Capacity)
		{
			unsigned int capacity = m_Capacity * 2;
			while(capacity <= m_Size + size)
			{
				capacity *= 2;
			}

			Reserve(capacity);
		}

		memcpy(m_Data + m_Size, data, sizeof(T) * size);
		m_Size += size;
	}

	inline unsigned int GetCapacity() const
	{
		return m_Capacity;
	}

	inline unsigned int GetSize() const
	{
		return m_Size;
	}

	inline T const * GetData() const
	{
		return m_Data;
	}

	inline void Clear();

private:
protected:
	T* m_Data;
	unsigned int m_Size;
	unsigned int m_Capacity;
};

} // common
} // projectcos

#endif /* BUFFER_H_ */
